<?php

declare(strict_types=1);

namespace App\Controller;

use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\Redis\Redis;
use Hyperf\Utils\ApplicationContext;
use Swoole\Server;
use Trait\ResponseMsg;
use App\Model\Normal;

class DeviceController extends AbstractController
{
    use ResponseMsg;

    protected Redis $redis;
    protected Normal $normal;

    public function __construct()
    {
        $this->redis = ApplicationContext::getContainer()->get(Redis::class);
        $this->normal = ApplicationContext::getContainer()->get(Normal::class);
    }

    public function convertToBCD(string $deviceId): string
    {
        // 只保留数字字符
        $cleaned = preg_replace('/[^\d]/', '', $deviceId);

        // 确保长度为偶数
        if (strlen($cleaned) % 2 != 0) {
            $cleaned = '0' . $cleaned;
        }

        $bcd = '';

        // 每两位数字转换为一个BCD字节
        for ($i = 0; $i < strlen($cleaned); $i += 2) {
            $high = (int)substr($cleaned, $i, 1);
            $low = (int)substr($cleaned, $i + 1, 1);
            $bcd .= chr(($high << 4) | $low);
        }

        // 确保长度为8字节，不足则左补0
        while (strlen($bcd) < 8) {
            $bcd = chr(0x00) . $bcd;
        }

        // 如果超过8字节则截断
        if (strlen($bcd) > 8) {
            $bcd = substr($bcd, -8);
        }

        return $bcd;
    }

    public function convertToFixedASCII(string $deviceId, int $length = 8): string
    {
        // 清理输入（只保留可打印字符）
        $cleaned = preg_replace('/[^\x20-\x7E]/', '', $deviceId);

        // 截取或填充到指定长度
        if (strlen($cleaned) > $length) {
            $result = substr($cleaned, 0, $length);
        } else {
            $result = str_pad($cleaned, $length, "\0", STR_PAD_RIGHT);
        }

        // 添加调试日志
        Normal::logger(sprintf(
            "设备号转换: 输入=%s, 输出(HEX)=%s",
            $deviceId,
            bin2hex($result)
        ), 'order-event');

        return $result;
    }

    /**开启命令
     * @param RequestInterface $request
     * @return \Psr\Http\Message\ResponseInterface
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public function start(RequestInterface $request)
    {
        $fd = $request->input('fd', 0);
        $chargerId = $request->input('sn');
        $gunNumber = $request->input('channel_number');
        $orderId = $request->input('number');
        $duration = $request->input('duration');
        $balance = $request->input('power_fee');

        try {
            $fd = (int)$fd;
            $server = ApplicationContext::getContainer()->get(Server::class);

            // 检查连接是否存在
            if ($server->exists($fd)) {
                Normal::logger("发送远程启动充电命令 - 参数: FD={$fd}, SN={$chargerId}, Gun={$gunNumber}, Order={$orderId}, Duration={$duration}, Balance={$balance}", 'order-event');

                // 构建远程启动充电命令(0x84)
                $message = $this->buildRemoteStartCommand(
                    $chargerId,
                    (int)$gunNumber,
                    (int)$orderId,
                    (int)$duration,
                    (int)$balance
                );

                // 记录十六进制格式的消息
                Normal::logger($fd.' 构建的命令消息(HEX): '.bin2hex($message), 'order-event');

                $result = $server->send($fd, $message);

                if ($result) {
                    Normal::logger($fd.' 发送远程启动命令成功', 'order-event');
                    return $this->success(['message' => '命令发送成功']);
                } else {
                    Normal::logger($fd.' 发送远程启动命令失败', 'order-event');
                    return $this->error(1001,'命令发送失败');
                }
            } else {
                Normal::logger($fd.' 连接失效', 'order-event');
                return $this->error(1002,'设备连接失效');
            }
        } catch (\Exception $e) {
            Normal::logger('发送远程启动命令错误: ' . $e->getMessage() . ' Trace: ' . $e->getTraceAsString(), 'order-event');
            return $this->error(1001,'发送命令失败: '.$e->getMessage());
        }
    }


    /**结束命令
     * @param RequestInterface $request
     * @return \Psr\Http\Message\ResponseInterface
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public function stop(RequestInterface $request)
    {
        $fd = $request->input('fd', 0);
        $chargerId = $request->input('sn');
        $gunNumber = $request->input('channel_number');
        $orderId = $request->input('number');
        $balance = $request->input('balance', 0);

        try {
            $fd = (int)$fd;
            $server = ApplicationContext::getContainer()->get(Server::class);

            // 检查连接是否存在
            if ($server->exists($fd)) {
                Normal::logger("发送远程结束充电命令 - 参数: FD={$fd}, SN={$chargerId}, Gun={$gunNumber}, Order={$orderId}, Balance={$balance}", 'order-event');

                // 构建远程结束充电命令(0x85)
                $message = $this->buildRemoteStopCommand(
                    $chargerId,
                    (int)$gunNumber,
                    (int)$orderId,
                    (int)$balance
                );

                // 记录十六进制格式的消息
                Normal::logger($fd.' 构建的结束命令消息(HEX): '.bin2hex($message), 'order-event');

                $result = $server->send($fd, $message);

                if ($result) {
                    Normal::logger($fd.' 发送远程结束命令成功', 'order-event');
                    return $this->success(['message' => '命令发送成功']);
                } else {
                    Normal::logger($fd.' 发送远程结束命令失败', 'order-event');
                    return $this->error(1001,'命令发送失败');
                }
            } else {
                Normal::logger($fd.' 连接失效', 'order-event');
                return $this->error(1002,'设备连接失效');
            }
        } catch (\Exception $e) {
            Normal::logger('发送远程结束命令错误: ' . $e->getMessage() . ' Trace: ' . $e->getTraceAsString(), 'order-event');
            return $this->error(1001,'发送命令失败: '.$e->getMessage());
        }
    }

    private function buildRemoteStopCommand(string $chargerId, int $gunNumber, int $orderId, int $balance): string
    {
        $body = '';

        // 1. 桩编号 ASCII 8字节（固定长度，右补0）
        $body .= $this->convertToBCD($chargerId);

        // 2. 枪号 BIN 1字节
        $body .= pack('C', $gunNumber);

        // 3. 订单号 BIN 8字节 (64位大端序)
        $body .= $this->packUint64($orderId);

        // 4. 余额 BIN 4字节 (单位分，32位大端序)
        $body .= pack('N', $balance);

        // 构建完整消息帧
        return $this->buildFrame(0x85, $body);
    }



    private function buildRemoteStartCommand(string $chargerId, int $gunNumber, int $orderId, int $duration, int $balance): string
    {
        $body = '';

        // 1. 桩编号 ASCII 8字节（固定长度，右补0）
        $body .= $this->convertToBCD($chargerId);

        // 2. 枪号 BIN 1字节
        $body .= pack('C', $gunNumber);

        // 3. 订单号 BIN 8字节 (64位大端序)
        $body .= $this->packUint64($orderId);

        // 4. 充电时长 BIN 2字节 (秒，16位大端序)
        $body .= pack('n', $duration);

        // 5. 账户余额 BIN 4字节 (单位分，32位大端序)
        $body .= pack('N', $balance);

        // 构建完整消息帧
        return $this->buildFrame(0x84, $body);
    }

    private function packUint64(int $value): string
    {
        return pack('J', $value);
    }

    private function buildFrame(int $command, string $body): string
    {
        // 帧头
        $frame = chr(0x68);

        // 命令码
        $frame .= chr($command);

        // 序列号
        $seq = $this->generateSequence();
        $frame .= pack('n', $seq); // 大端序

        // 消息体长度 (大端序)
        $bodyLength = strlen($body);
        $frame .= pack('n', $bodyLength);

        // 消息体
        $frame .= $body;

        // CRC校验范围：从命令码到消息体结束
        $crcData = substr($frame, 1);
        $crc = $this->calculateCrc($crcData);
        $frame .= pack('n', $crc); // 大端序

        // 调试输出完整报文
        Normal::logger('完整报文帧(HEX): ' . bin2hex($frame), 'order-event');
        return $frame;
    }

    private function calculateCrc(string $data): int
    {
        $crc = 0x0000;
        $polynomial = 0x1021;

        for ($i = 0; $i < strlen($data); $i++) {
            $byte = ord($data[$i]);
            for ($j = 0; $j < 8; $j++) {
                $bit = (($byte >> (7 - $j)) & 1) == 1;
                $c15 = (($crc >> 15) & 1) == 1;
                $crc <<= 1;
                if ($c15 ^ $bit) {
                    $crc ^= $polynomial;
                }
            }
        }

        return $crc & 0xFFFF;
    }

    private function generateSequence(): int
    {
        static $sequence = 0;
        $sequence = ($sequence + 1) % 65536;
        return $sequence;
    }

    public function formatDevice(RequestInterface $request)
    {
        $deviceId = $request->input('sn');
        return $this->formatDeviceId($deviceId);
    }

/**
* 将设备号格式化为16字符的十六进制字符串
* @param mixed $deviceId 设备号
* @param bool $uppercase 是否大写
* @return string 16字符的十六进制字符串
*/
    public function formatDeviceId($deviceId, bool $uppercase = true): string
    {
        // 验证并转换输入
        if (!is_numeric($deviceId)) {
            throw new \InvalidArgumentException("设备号必须是数字");
        }

        $id = (int)$deviceId;

        // 转换为十六进制
        $hex = dechex($id);

        // 左补零到16个字符（8字节）
        $result = str_pad($hex, 16, '0', STR_PAD_LEFT);

        // 处理长度超过16字符的情况（截断）
        if (strlen($result) > 16) {
            $result = substr($result, -16);
        }

        return $uppercase ? strtoupper($result) : $result;
    }

    /**重启设备
     * @param RequestInterface $request
     * @return \Psr\Http\Message\ResponseInterface
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public function restart(RequestInterface $request)
    {
        $fd = $request->input('fd', 0);
        $chargerId = $request->input('sn');

        try {
            $fd = (int)$fd;
            $server = ApplicationContext::getContainer()->get(Server::class);

            // 检查连接是否存在
            if ($server->exists($fd)) {
                Normal::logger("发送重启命令 - 参数: FD={$fd}, SN={$chargerId}", 'order-event');

                // 构建重启命令(0x8A)
                $message = $this->buildRestartCommand($chargerId);

                // 记录十六进制格式的消息
                Normal::logger($fd.' 构建的重启命令消息(HEX): '.bin2hex($message), 'order-event');

                $result = $server->send($fd, $message);

                if ($result) {
                    Normal::logger($fd.' 发送重启命令成功', 'order-event');
                    return $this->success(['message' => '重启命令发送成功']);
                } else {
                    Normal::logger($fd.' 发送重启命令失败', 'order-event');
                    return $this->error(1001,'重启命令发送失败');
                }
            } else {
                Normal::logger($fd.' 连接失效', 'order-event');
                return $this->error(1002,'设备连接失效');
            }
        } catch (\Exception $e) {
            Normal::logger('发送重启命令错误: ' . $e->getMessage() . ' Trace: ' . $e->getTraceAsString(), 'order-event');
            return $this->error(1001,'发送命令失败: '.$e->getMessage());
        }
    }

    private function buildRestartCommand(string $chargerId): string
    {
        $body = '';

        // 1. 桩编号 BCD 8字节
        $body .= $this->convertToBCD($chargerId);

        // 构建完整消息帧
        return $this->buildFrame(0x8A, $body);
    }

    private function buildCoinParametersCommand(string $chargerId, int $minutes): string
    {
        $body = '';

        // 1. 桩编号 BCD 8字节
        $body .= $this->convertToBCD($chargerId);

        // 2. 投币时间 BIN 2字节 (单位分钟，16位大端序)
        $body .= pack('n', $minutes);

        // 构建完整消息帧
        return $this->buildFrame(0x91, $body);
    }


    public function setCoin(RequestInterface $request){
        Normal::logger(json_encode($request->post()),'order-event');
        $fd = $request->input('fd', 0);
        $chargerId = $request->input('sn');
        $minutes = $request->input('minutes', 0);
        try {
            $fd = (int)$fd;
            $server = ApplicationContext::getContainer()->get(Server::class);
            if ($server->exists($fd)) {
                Normal::logger("发送设备投币命令 - 参数: FD={$fd}, SN={$chargerId}", 'order-event');

                // 构建设备参数设置命令(0x8D)
                $message = $this->buildCoinParametersCommand(
                    $chargerId,
                    (int)$minutes
                );
                // 记录十六进制格式的消息
                Normal::logger($fd.' 构建的参数设置命令消息(HEX): '.bin2hex($message), 'order-event');
                $result = $server->send($fd, $message);
                if ($result) {
                    Normal::logger($fd.' 发送设备参数设置命令成功', 'order-event');
                    return $this->success(['message' => '参数设置命令发送成功']);
                } else {
                    Normal::logger($fd.' 发送设备参数设置命令失败', 'order-event');
                    return $this->error(1001,'参数设置命令发送失败');
                }
            } else {
                Normal::logger($fd.' 连接失效', 'order-event');
                return $this->error(1002,'设备连接失效');
            }
        }catch (\Exception $e){
            Normal::logger('发送设备投币设置命令错误: ' . $e->getMessage() . ' Trace: ' . $e->getTraceAsString(), 'order-event');
            return $this->error(1001,'发送命令失败: '.$e->getMessage());
        }
    }

    /**设置设备
     * @param RequestInterface $request
     * @return \Psr\Http\Message\ResponseInterface
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public function setDeviceParameters(RequestInterface $request)
    {
        Normal::logger(json_encode($request->post()),'order-event');
        $fd = $request->input('fd', 0);
        $chargerId = $request->input('sn');
        $heartbeatInterval = $request->input('heart_cycle', 20); // 心跳间隔(秒)
        $statusReportInterval = $request->input('report_cycle', 60); // 状态上报间隔(秒)
        $floatChargePower = $request->input('full_charge_power', 50); // 浮充功率(瓦)
        $floatChargeTime = $request->input('full_charge_delay', 300); // 浮充时间(秒)
        $zeroPowerTime = $request->input('null_charge_delay', 120); // 功率为零时间(秒)
        $singleMaxPower = $request->input('single_max_power', 2000); // 单路最大功率(瓦)
        $maxChargeTime = $request->input('max_charge_time', 3600); // 最大充电时长(秒)

        try {
            $fd = (int)$fd;
            $server = ApplicationContext::getContainer()->get(Server::class);

            // 检查连接是否存在
            if ($server->exists($fd)) {
                Normal::logger("发送设备参数设置命令 - 参数: FD={$fd}, SN={$chargerId}", 'order-event');

                // 构建设备参数设置命令(0x8D)
                $message = $this->buildSetDeviceParametersCommand(
                    $chargerId,
                    (int)$heartbeatInterval,
                    (int)$statusReportInterval,
                    (int)$floatChargePower,
                    (int)$floatChargeTime,
                    (int)$zeroPowerTime,
                    (int)$singleMaxPower,
                    (int)$maxChargeTime
                );

                // 记录十六进制格式的消息
                Normal::logger($fd.' 构建的参数设置命令消息(HEX): '.bin2hex($message), 'order-event');

                $result = $server->send($fd, $message);

                if ($result) {
                    Normal::logger($fd.' 发送设备参数设置命令成功', 'order-event');
                    return $this->success(['message' => '参数设置命令发送成功']);
                } else {
                    Normal::logger($fd.' 发送设备参数设置命令失败', 'order-event');
                    return $this->error(1001,'参数设置命令发送失败');
                }
            } else {
                Normal::logger($fd.' 连接失效', 'order-event');
                return $this->error(1002,'设备连接失效');
            }
        } catch (\Exception $e) {
            Normal::logger('发送设备参数设置命令错误: ' . $e->getMessage() . ' Trace: ' . $e->getTraceAsString(), 'order-event');
            return $this->error(1001,'发送命令失败: '.$e->getMessage());
        }
    }

    private function buildSetDeviceParametersCommand(
        string $chargerId,
        int $heartbeatInterval,
        int $statusReportInterval,
        int $floatChargePower,
        int $floatChargeTime,
        int $zeroPowerTime,
        int $singleMaxPower,
        int $maxChargeTime
    ): string {
        $body = '';
        Normal::logger($heartbeatInterval.'-'.$statusReportInterval.'-'.$floatChargePower.'-'.$floatChargeTime.'-'.$zeroPowerTime.'-'.$singleMaxPower.'-'.$maxChargeTime,'order-event');
        // 1. 桩编号 BCD 8字节
        $body .= $this->convertToBCD($chargerId);

        // 2. 心跳间隔 BIN 2字节 (单位秒，16位大端序)
        $body .= pack('n', $heartbeatInterval);

        // 3. 状态上报间隔 BIN 2字节 (单位秒，16位大端序)
        $body .= pack('n', $statusReportInterval);

        // 4. 浮充功率 BIN 2字节 (单位瓦，16位大端序)
        $body .= pack('n', $floatChargePower);

        // 5. 浮充时间 BIN 2字节 (单位秒，16位大端序)
        $body .= pack('n', $floatChargeTime);

        // 6. 功率为零时间 BIN 2字节 (单位秒，16位大端序)
        $body .= pack('n', $zeroPowerTime);

        // 7. 单路最大功率 BIN 2字节 (单位瓦，16位大端序)
        $body .= pack('n', $singleMaxPower);

        // 8. 最大充电时长 BIN 2字节 (单位秒，16位大端序)
        $body .= pack('n', $maxChargeTime);

        // 构建完整消息帧
        return $this->buildFrame(0x8D, $body);
    }


    /**读取设备
     * @param RequestInterface $request
     * @return \Psr\Http\Message\ResponseInterface
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public function getDeviceParameters(RequestInterface $request)
    {
        $fd = $request->input('fd', 0);
        $chargerId = $request->input('sn');
        Normal::logger(__METHOD__.'-----'.$chargerId.'---'.$fd,'order-event');
        try {
            $fd = (int)$fd;
            $server = ApplicationContext::getContainer()->get(Server::class);

            // 检查连接是否存在
            if ($server->exists($fd)) {
                Normal::logger("发送设备参数读取命令 - 参数: FD={$fd}, SN={$chargerId}", 'order-event');

                // 构建设备参数读取命令(0x8C)
                $message = $this->buildGetDeviceParametersCommand($chargerId);

                // 记录十六进制格式的消息
                Normal::logger($fd.' 构建的参数读取命令消息(HEX): '.bin2hex($message), 'order-event');

                $result = $server->send($fd, $message);

                if ($result) {
                    Normal::logger($fd.' 发送设备参数读取命令成功', 'order-event');
                    return $this->success(['message' => '参数读取命令发送成功']);
                } else {
                    Normal::logger($fd.' 发送设备参数读取命令失败', 'order-event');
                    return $this->error(1001,'参数读取命令发送失败');
                }
            } else {
                Normal::logger($fd.' 连接失效', 'order-event');
                return $this->error(1002,'设备连接失效');
            }
        } catch (\Exception $e) {
            Normal::logger('发送设备参数读取命令错误: ' . $e->getMessage() . ' Trace: ' . $e->getTraceAsString(), 'order-event');
            return $this->error(1001,'发送命令失败: '.$e->getMessage());
        }
    }

    private function buildGetDeviceParametersCommand(string $chargerId): string
    {
        $body = '';

        // 1. 桩编号 BCD 8字节
        $body .= $this->convertToBCD($chargerId);

        // 构建完整消息帧
        return $this->buildFrame(0x8C, $body);
    }



}
